#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <iwlib.h>
#include <wireless.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/param.h>

#define MAC_ADDR_LEN			6							/* AP MAC address length */
#define HASH_ADDR_LEN			5							/* Hasded MAC address length */
#define SHORT_SAMPLE_COUNT		2							/* round number of short scan */
#define WIFI_SAMPLE_COUNT		10							/* round number of regular scan */
#define INVALID_RSSI			100							/* default value for rssi unreachable */
#define LOC_NAME_LEN			10							/* maximum number of characters in location name */
#define MAX_IFNAME_LEN			6							/* maximum length of interface name */
#define MAX_NUM_ROOMS			10							/* maximun map files */			
#define BLUEPIN_EIR_TYPE		0x2F						/* bp specified eir type */
#define STORAGEDIR				"/var/lib/bluetooth"		/* path to eir data file */ 

/* flags */
#define WBMODE					0x01						/*0001*/
#define BTMODE					0x02						/*0010*/	
#define WIFIMODE				0x04						/*0100*/
#define DATAMODE				0x08						/*1000*/

/* global parameter */
extern char myposition[];						/*current position of device*/

/**
 * struct configparam: 
 * 		global configuration information, created with rssi_map structure
 */
struct configparam{
	char wifi_ifname[MAX_IFNAME_LEN];		/* wifi interface */
	unsigned char  modeflag;						/* mode flag */
	int fusebcon;							/* fuse beacon only*/
	int setbcon;							/* set up beacon site permission */
	int shortscan;							/* wifi scan mode */
	int inqdura;							/* inquiry duration */
	int threshold;							/* signal distance threshold */
	int num_rooms;							/* number of map files */
	int rmarray[MAX_NUM_ROOMS]; 		/* room numbers for map file */
};

/**
 * struct rssi_bind: 
 * 		the basic structure for storing the information learnt from a serial of Wi-Fi scans. 
 * 		it comprises a linked list indexed by the hashed AP address, and sorted in ascending order. 
 * 		the tail element is a sentinel node with hashed address of all 0xFF and 0 sample_cnt
 */
struct rssi_bind{
	u_char macaddr[MAC_ADDR_LEN];				/* complete mac address of AP */			
	u_char hashaddr[HASH_ADDR_LEN];				/* hashed mac address of AP */
	int sample_db[WIFI_SAMPLE_COUNT];			/* rssi array, recording rssi report from each wifi scan */
	int sample_cnt; 							/* AP actually appears, out of WIFI_SAMPLE_COUNT */
	int mean_db;								/* mean of rssi values from all scans */
	double stddev_db;							/* standard deviation of rssi values from all scans */
	struct rssi_bind *next;						/* pointer to next bind element in the linked list */
};

/**
 * struct rssi_fgpt: 
 * 		RSSI fingerprint structure, associating the location info with corresponding rssi_bind list.
 *		it comprises a linked list indexed by location identifier. the list is unsorted
 * 		the tail element is also a sentinel node and can be identified with a NULL next pointer
 */
struct rssi_fgpt{
	char loc[LOC_NAME_LEN+1];					/* location information, a string */
	int commited;								/* this is fingerprint is commited or just reported */
	int bind_cnt;								/* number of APs in the scan list, INCLUDING the tail element */
	struct rssi_bind *bind_head;				/* pointer to the head element of rssi_bind list */
	struct rssi_fgpt *next;						/* pointer to next fingerprint element in the linked list */
	/* TODO: add expire timer? */
};

/**
 * struct rssi_map: 
 * 		RSSI fingerprint map, local cache of all sensed rssi fingerprints 
 * 		fingerprints may come from wifi scan, received bluetooth beacons, or fingerprint log file/database server
 *          The first element is always fingerprint representing the local scan
 * 		same location can have multiple fingerprints in a map, at different map positions
 */
struct rssi_map{
	int fgpt_cnt;								/* number of fingerprints in the map, INCLUDING the tail element */
	struct rssi_fgpt *fgpt_head;				/* pointer to the head element of rssi_fgpt list */
	struct rssi_fgpt *fgpt_tail;				/* pointer to the end of cache map */
	struct configparam *globalconfig; 			/* configuration parameters */
};

struct rssi_bind* rssibind_init(void);
int rssifgpt_print(struct rssi_fgpt *rssifgpt, FILE *debug);
int rssifgpt_update_wifi(struct rssi_fgpt *local, struct wireless_scan_head *wsh, int round, int scan_num);
int rssifgpt_update_bcon(struct rssi_fgpt *rssifgpt, char *eirdata);
struct rssi_map * rssimap_init(void);
int rssimap_free(struct rssi_map *rssimap);
int rssimap_print(struct rssi_map *rssimap, FILE *debug);
int rssimap_fuse(struct rssi_map *rssimap, int fusebcon);
int rssimap_load_cache(struct rssi_map *rssimap);
int rssimap_load_local_file(struct rssi_map *rssimap, int localroom, int localpos);
double rssimap_localizer(struct rssi_map *rssimap, int fusebcon, FILE *debug);
int scanner_wifi(struct rssi_map *rssimap, int shortscan);
int scanner_bt(struct rssi_map *rssimap, int inq_duration);
int addrcmp(char *ha_local, char *ha_peer);
void addrhash(u_char *mac_addr, u_char *hash_addr);
int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data);
int btbcon_prompt(struct rssi_map *rssimap);


